package com.ruoyi.asset.recycle.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.asset.common.scopecode.constant.ServiceCode;
import com.ruoyi.asset.common.scopecode.service.IScopeCodeService;
import com.ruoyi.asset.homepage.constant.CommunityConstant;
import com.ruoyi.asset.homepage.constant.ServiceTypeConstant;
import com.ruoyi.asset.recycle.constant.WasteRecycleDirtConstant;
import com.ruoyi.asset.recycle.domain.WasteRecycle;
import com.ruoyi.asset.recycle.domain.bo.*;
import com.ruoyi.asset.recycle.domain.vo.RecycleCommunityCountVo;
import com.ruoyi.asset.recycle.domain.vo.RecycleWorkStatisticsVo;
import com.ruoyi.asset.recycle.domain.vo.WasteRecycleVo;
import com.ruoyi.asset.recycle.mapper.WasteRecycleMapper;
import com.ruoyi.asset.recycle.service.IWasteRecycleService;
import com.ruoyi.asset.tool.domain.bo.ToolStatisticsBo;
import com.ruoyi.asset.tool.service.IToolService;
import com.ruoyi.asset.workman.service.IWorkmanService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.tools.excel.MyExcelUtil;
import com.ruoyi.common.tools.excel.base.MyExcelResult;
import com.ruoyi.common.tools.excel.listener.asset.RecycleExcelListener;
import com.ruoyi.common.tools.utils.SerialGenerator;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.erecord.region.service.IRegionService;
import com.ruoyi.standingbook.recycle.service.IRecycleService;
import com.ruoyi.system.service.ISysDictDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 12276
 */
@RequiredArgsConstructor
@Service
public class WasteRecycleServiceImpl implements IWasteRecycleService {

    private final WasteRecycleMapper wasteRecycleMapper;
    private final IRecycleService recycleService;
    private final IToolService toolService = SpringUtils.getBean(IToolService.class);
    private final IRegionService regionService = SpringUtils.getBean(IRegionService.class);
    private final IWorkmanService workmanService = SpringUtils.getBean(IWorkmanService.class);
    private final ISysDictDataService sysDictDataService = SpringUtils.getBean(ISysDictDataService.class);

    private final IScopeCodeService scopeCodeService;

    private Boolean batchInsertOrUpdate(List<WasteRecycle> voList) {
        return this.wasteRecycleMapper.insertOrUpdateBatch(voList);
    }

    @Override
    public List<String> importExcel(String excelUrl) {
        List<String> errorMsgList = new ArrayList<>();

        // 生成批次号
        final String batchNo = SerialGenerator.generator.nextId();

        // excel 处理
        MyExcelResult<WasteRecycleVo> excelResult = MyExcelUtil.getImportExcelData(batchNo, excelUrl,
            new RecycleExcelListener(batchNo), WasteRecycleVo.class, true);

        if (null == excelResult) {
            errorMsgList.add("未获取到要处理的数据");

            return null;
        }

        /**
         *  有解析失败就直接返回错误信息
         */
        if (!excelResult.getErrorList().isEmpty()) {
            return excelResult.getErrorList();
        }

        if (!excelResult.getList().isEmpty()) {
            List<WasteRecycle> list = new ArrayList<>();
            AtomicInteger row = new AtomicInteger(0);
            excelResult.getList().forEach(e -> {
                int currentRow = row.incrementAndGet();
                if (e.getDataCheckResult().isSucess()) {
                    WasteRecycle wasteRecycle = new WasteRecycle();

                    BeanCopyUtils.copy(e, wasteRecycle);

                    WasteRecycle oldLampMaintenance = getVoByCondition(wasteRecycle.getRecyclePointName(),
                        wasteRecycle.getYear(), wasteRecycle.getGarbageType());

                    if (oldLampMaintenance != null) {
                        wasteRecycle.setId(oldLampMaintenance.getId());
                    } else {
                        String scopeCode = null;

                        try {
                            scopeCode = scopeCodeService.getNextScopeCode(ServiceCode.RECYCLE,
                                wasteRecycle.getGarbageType(), "");
                        } catch (Exception ex) {
                            errorMsgList.add("获取管理范围编码失败，失败原因：" + ex.getMessage());
                        }

                        wasteRecycle.setRecyclePointCode(scopeCode);
                    }

                    /**
                     *  如果各行数据校验通过，再遍历检查是否数据重复
                     */
                    if (excelResult.getValidateList().isEmpty()) {
                        AtomicInteger count = new AtomicInteger(0);
                        list.stream().anyMatch(f -> {
                            int currentCount = count.incrementAndGet();
                            if (f.getRecyclePointName().equals(wasteRecycle.getRecyclePointName()) && f.getGarbageType().equals(wasteRecycle.getGarbageType()) && f.getYear().equals(wasteRecycle.getYear())) {
                                errorMsgList.add(String.format("第%d行数据检查失败，失败原因：与第%s行数据重复", currentRow, currentCount));
                                return true;
                            }
                            return false;
                        });
                    }

                    list.add(wasteRecycle);
                } else {
                    errorMsgList.add(String.format("第 %d 行数据检查失败，失败原因：%s", currentRow, e.getDataCheckResult().getMsg()));
                }
            });

            if (errorMsgList.isEmpty()) {
                batchInsertOrUpdate(list);
            }
        }

        return errorMsgList;
    }

    private WasteRecycle getVoByCondition(String recyclePointName, String year, String garbageType) {
        LambdaQueryWrapper<WasteRecycle> lqw = Wrappers.lambdaQuery();

        lqw.eq(WasteRecycle::getRecyclePointName, recyclePointName);
        lqw.eq(WasteRecycle::getYear, year);
        lqw.eq(WasteRecycle::getGarbageType, garbageType);
        lqw.eq(WasteRecycle::getDelFlag, 0);

        List<WasteRecycle> list = wasteRecycleMapper.selectList(lqw);

        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public int deleteRecycle(Set<Long> idsSet) {
        if (CollectionUtils.isEmpty(idsSet)) {
            return -1;
        }
        return wasteRecycleMapper.logicDeleteRecycle(idsSet);
    }

    @Override
    public TableDataInfo<WasteRecycleVo> queryRecycle(WasteRecycleBo searchBo, PageQuery pageQuery) {
        Page<WasteRecycleVo> result = wasteRecycleMapper.selectRecyclePage(pageQuery.build(), searchBo);
        ArrayList<WasteRecycleVo> list = new ArrayList<>();
        result.getRecords().forEach(e -> {
            WasteRecycleVo wasteRecycleVo = new WasteRecycleVo();
            BeanCopyUtils.copy(e, wasteRecycleVo);
            String garbageType = sysDictDataService.selectDictLabel(WasteRecycleDirtConstant.RECYCLE_TYPE, wasteRecycleVo.getGarbageType());
            if (StringUtils.isNotBlank(garbageType)) {
                wasteRecycleVo.setGarbageType(garbageType);
            }
            String year = sysDictDataService.selectDictLabel(WasteRecycleDirtConstant.RECYCLE_YEAR, wasteRecycleVo.getYear());
            if (StringUtils.isNotBlank(year)) {
                wasteRecycleVo.setYear(year);
            }
            list.add(wasteRecycleVo);

        });
        result.setRecords(list);
        return TableDataInfo.build(result);
    }

    @Override
    public List<WasteRecycleVo> exportRecycle(WasteRecycleBo searchBo) {
        ArrayList<WasteRecycleVo> list = new ArrayList<>();
        wasteRecycleMapper.exportRecycle(searchBo).forEach(e -> {
            WasteRecycleVo wasteRecycleVo = new WasteRecycleVo();
            BeanCopyUtils.copy(e, wasteRecycleVo);
            String garbageType = sysDictDataService.selectDictLabel(WasteRecycleDirtConstant.RECYCLE_TYPE, wasteRecycleVo.getGarbageType());
            if (StringUtils.isNotBlank(garbageType)) {
                wasteRecycleVo.setGarbageType(garbageType);
            }
            String year = sysDictDataService.selectDictLabel(WasteRecycleDirtConstant.RECYCLE_YEAR, wasteRecycleVo.getYear());
            if (StringUtils.isNotBlank(year)) {
                wasteRecycleVo.setYear(year);
            }
            list.add(wasteRecycleVo);

        });
        return list;
    }

    @Override
    public WasteRecycleStatisticsBo getRecycleCount() {
        WasteRecycleStatisticsBo statisticsBo = new WasteRecycleStatisticsBo();
        Integer numCount = wasteRecycleMapper.selectNumCount();
        statisticsBo.setRecyclePointCount(numCount);
        Double weightSum = wasteRecycleMapper.selectWeightSum();
        if (null != weightSum) {
            statisticsBo.setWeightCount(BigDecimal.valueOf(weightSum).setScale(2, RoundingMode.HALF_UP));
        } else {
            statisticsBo.setWeightCount(BigDecimal.ZERO);
        }
        int workCount = workmanService.getByServiceType(ServiceTypeConstant.RECYCLE);
        statisticsBo.setWorkerCount(workCount);
        ToolStatisticsBo toolStatisticsBo = toolService.getCountByServiceType(ServiceTypeConstant.RECYCLE);
        if (null != toolStatisticsBo) {
            statisticsBo.setEquipmentCount(toolStatisticsBo.getToolCount());
            statisticsBo.setVehicleCount(toolStatisticsBo.getVehicleCount());
        } else {
            statisticsBo.setEquipmentCount(0);
            statisticsBo.setVehicleCount(0);
        }
        return statisticsBo;
    }

    @Override
    public Map getRecycleCommunityCount() {
        HashMap<String, RecycleCommunityBo> map = new HashMap<>();
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> data = sysDictDataService.selectDictDataList(sysDictData);
        for (SysDictData community : data) {
            String communityNo = regionService.getRegionIdByName(community.getDictLabel());
            Integer pointCount = wasteRecycleMapper.selectCommunityPointCount(communityNo);
            List<RecycleTypeBo> recycleTypeBos = wasteRecycleMapper.selectCommunityTypeCount(communityNo);
            recycleTypeBos.forEach(e -> {
                String garbageName = sysDictDataService.selectDictLabel(WasteRecycleDirtConstant.RECYCLE_TYPE, e.getGarbageType());
                if (StringUtils.isNotBlank(garbageName)) {
                    e.setGarbageType(garbageName);
                }
            });
            RecycleCommunityBo recycleCommunityBo = new RecycleCommunityBo();
            recycleCommunityBo.setRecyclePointCount(pointCount);
            recycleCommunityBo.setRecycleTypeBoList(recycleTypeBos);
            ToolStatisticsBo toolCount = toolService.getCountByServiceTypeAndCommunity(ServiceTypeConstant.RECYCLE, communityNo);
            recycleCommunityBo.setToolCount(toolCount.getToolCount());
            recycleCommunityBo.setVehicleCount(toolCount.getVehicleCount());
            int workmanCount = workmanService.getCommunityByServiceType(ServiceTypeConstant.RECYCLE, communityNo);
            recycleCommunityBo.setWorkmanCommunity(workmanCount);
            map.put(community.getDictLabel(), recycleCommunityBo);
        }
        return map;
    }

    @Override
    public List<RecycleCommunityCountVo> getRecycleCountByCommunity(String date) {
        String[] split = date.split("-");
        String year = split[0];
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        ArrayList<RecycleCommunityCountVo> recycleCommunityCountVos = new ArrayList<>();
        communities.forEach(e -> {
            RecycleCommunityCountVo recycleCommunityCountVo = new RecycleCommunityCountVo();
            recycleCommunityCountVo.setCommunity(e.getDictLabel());
            String regionId = regionService.getRegionIdByName(e.getDictLabel());
            Integer recycleNumSum = wasteRecycleMapper.selectRecycleNumByCommunity(date, year, regionId);
            recycleCommunityCountVo.setRecyclePointSum(recycleNumSum.toString());
            Double recycleWeightSum = wasteRecycleMapper.selectRecycleWeightByCommunity(date, year, regionId);
            if (null != recycleWeightSum) {
                recycleCommunityCountVo.setWeightSum(recycleWeightSum.toString());
            } else {
                recycleCommunityCountVo.setWeightSum("0");
            }
            ToolStatisticsBo toolCount = toolService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.RECYCLE, regionId, date);
            if (null != toolCount) {
                recycleCommunityCountVo.setEquipmentCount(toolCount.getToolCount());
                recycleCommunityCountVo.setVehicleCount(toolCount.getVehicleCount());
            } else {
                recycleCommunityCountVo.setEquipmentCount(0);
                recycleCommunityCountVo.setVehicleCount(0);
            }
            int workmanCount = workmanService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.RECYCLE, regionId, date);
            recycleCommunityCountVo.setWorkerCount(workmanCount);
            recycleCommunityCountVos.add(recycleCommunityCountVo);
        });

        return recycleCommunityCountVos;
    }

    @Override
    public RecycleWorkStatisticsVo getRecycleWorkByDate(String date) {
        String[] split = date.split("-");
        String year = split[0];
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        List<Double> weightSumList = new ArrayList<>();
        communities.forEach(e -> {
            String regionId = regionService.getRegionIdByName(e.getDictLabel());
            Double recycleWeightSum = wasteRecycleMapper.selectRecycleWeightByCommunity(date, year, regionId);
            if (null != recycleWeightSum) {
                weightSumList.add(recycleWeightSum);
            } else {
                weightSumList.add(0.00);
            }
        });
        RecycleWorkStatisticsVo recycleWorkStatisticsVo = new RecycleWorkStatisticsVo();
        Double weightSum = weightSumList.stream().reduce(Double::sum).orElse(0.00);
        BigDecimal avgWeight = BigDecimal.valueOf(weightSum / 365).setScale(2, RoundingMode.HALF_UP);
        if (avgWeight.compareTo(BigDecimal.ZERO) <= 0) {
            avgWeight = BigDecimal.ZERO;
        }
        recycleWorkStatisticsVo.setTotalWeight(avgWeight);
        Double weightSumByDate = recycleService.getWeightSumByDate(date);
        BigDecimal finishedWeightSum = BigDecimal.valueOf(weightSumByDate).divide(BigDecimal.valueOf(1000), 2, RoundingMode.HALF_UP);
        recycleWorkStatisticsVo.setFinishedWeightSum(finishedWeightSum);
        if (avgWeight.equals(BigDecimal.ZERO) || finishedWeightSum.equals(BigDecimal.ZERO)) {
            recycleWorkStatisticsVo.setPercent(BigDecimal.ZERO);
        } else {
            BigDecimal pec = finishedWeightSum.divide(avgWeight, 2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
            pec = pec.compareTo(BigDecimal.valueOf(100)) > 0 ? BigDecimal.valueOf(100) : pec;
            recycleWorkStatisticsVo.setPercent(pec);
        }
        return recycleWorkStatisticsVo;
    }

    @Override
    public RecycleCommunityCountVo getRecycleByDateAndCommunity(String date, String community) {
        Integer num ;
        Double weight;
        String year = Integer.toString(DateUtil.year(new Date()));
        if (StringUtils.isNotEmpty(community)) {
            String regionIdByName = regionService.getRegionIdByName(community);
            num = wasteRecycleMapper.selectRecycleNumByCommunity(date,year, regionIdByName);
            weight = wasteRecycleMapper.selectRecycleWeightByCommunity(date,year, regionIdByName);
        } else {
            num = wasteRecycleMapper.selectRecycleNumByCommunity(date, year, null);
            weight = wasteRecycleMapper.selectRecycleWeightByCommunity(date, year, null);
        }
        RecycleCommunityCountVo countVo = new RecycleCommunityCountVo();
        if (null == num) {
            num = 0;
        }
        if (null == weight) {
            weight = 0d;
        }
        countVo.setRecyclePointSum(num.toString());
        countVo.setWeightSum(weight.toString());
        return countVo;
    }

}
